/* ###################################### */
/* ###     Util Engine, by Kalith    ### */
/* ###################################### */
/*                                        */

#include "Maths.h"

#include <cmath>

#ifdef MSVC
    // Note : Microsoft's Visual C++ doesn't include the round function.
    long round( double x )
    {
        int i = static_cast<long>(x);
        if (x >= 0.0)
            return (x-i >= 0.5) ? i + 1 : i;
        else
            return (i-x >= 0.5) ? i - 1 : i;
    }
#endif

namespace Util
{
// Int

    Float cos(const Int& iValue)
    {
        return ::cos(iValue.Get()*2.0f*Float::PI.Get());
    }

    Float acos(const Int& iValue)
    {
        return Float(::acos(static_cast<float>(iValue.Get())))/(2.0f*Float::PI);
    }

    Float sin(const Int& iValue)
    {
        return ::sin(iValue.Get()*2.0f*Float::PI.Get());
    }

    Float asin(const Int& iValue)
    {
        return Float(::asin(static_cast<float>(iValue.Get())))/(2.0f*Float::PI);
    }

    Float tan(const Int& iValue)
    {
        return ::tan(iValue.Get()*2.0f*Float::PI.Get());
    }

    Float atan(const Int& iValue)
    {
        return Float(::atan(static_cast<float>(iValue.Get())))/(2.0f*Float::PI);
    }

    Float atan2(const Int& iX, const Int& iY)
    {
        return Float(::atan2(static_cast<float>(iX.Get()), static_cast<float>(iY.Get())))/(2.0f*Float::PI.Get());
    }

    Int fabs(const Int& iValue)
    {
        return static_cast<int>(::fabs(static_cast<float>(iValue.Get())));
    }

    Float pow(const Int& iValue, const Float& fValue)
    {
        return ::pow(static_cast<float>(iValue.Get()), static_cast<float>(fValue.Get()));
    }

    Double pow(const Int& iValue, const Double& dValue)
    {
        return ::pow(static_cast<double>(iValue.Get()), static_cast<double>(dValue.Get()));
    }

    Float sqrt(const Int& iValue)
    {
        return ::sqrt(static_cast<float>(iValue.Get()));
    }

    Float exp(const Int& iValue)
    {
        return ::exp(static_cast<float>(iValue.Get()));
    }

// UInt

    Float cos(const UInt& uiValue)
    {
        return ::cos(uiValue.Get()*2.0f*Float::PI.Get());
    }

    Float acos(const UInt& uiValue)
    {
        return Float(::acos(static_cast<float>(uiValue.Get())))/(2.0f*Float::PI);
    }

    Float sin(const UInt& uiValue)
    {
        return ::sin(uiValue.Get()*2*Float::PI.Get());
    }

    Float asin(const UInt& uiValue)
    {
        return Float(::asin(static_cast<float>(uiValue.Get())))/(2.0f*Float::PI);
    }

    Float tan(const UInt& uiValue)
    {
        return ::tan(uiValue.Get()*2.0f*Float::PI.Get());
    }

    Float atan(const UInt& uiValue)
    {
        return Float(::atan(static_cast<float>(uiValue.Get())))/(2.0f*Float::PI);
    }

    Float atan2(const UInt& uiX, const UInt& uiY)
    {
        return Float(::atan2(static_cast<float>(uiX.Get()), static_cast<float>(uiY.Get())))/(2.0f*Float::PI);
    }

    Float pow(const UInt& uiValue, const Float& fValue)
    {
        return ::pow(static_cast<float>(uiValue.Get()), static_cast<float>(fValue.Get()));
    }

    Double pow(const UInt& uiValue, const Double& dValue)
    {
        return ::pow(static_cast<double>(uiValue.Get()), static_cast<double>(dValue.Get()));
    }

    Float sqrt(const UInt& uiValue)
    {
        return ::sqrt(static_cast<float>(uiValue.Get()));
    }

    Float exp(const UInt& uiValue)
    {
        return ::exp(static_cast<float>(uiValue.Get()));
    }

// Float

    Float cos(const Float& fValue)
    {
        return ::cos((fValue*2.0f*Float::PI).Get());
    }

    Float acos(const Float& fValue)
    {
        return Float(::acos(fValue.Get()))/(2.0f*Float::PI);
    }

    Float sin(const Float& fValue)
    {
        return ::sin((fValue*2*Float::PI).Get());
    }

    Float asin(const Float& fValue)
    {
        return Float(::asin(fValue.Get()))/(2.0f*Float::PI);
    }

    Float tan(const Float& fValue)
    {
        return ::tan((fValue*2.0f*Float::PI).Get());
    }

    Float atan(const Float& fValue)
    {
        return Float(::atan(fValue.Get()))/(2.0f*Float::PI);
    }

    Float atan2(const Float& fX, const Float& fY)
    {
        return Float(::atan2(fX.Get(), fY.Get()))/(2.0f*Float::PI);
    }

    Float fabs(const Float& fValue)
    {
        return ::fabs(fValue.Get());
    }

    Float pow(const Float& fValue1, const Float& fValue2)
    {
        return ::pow(static_cast<float>(fValue1.Get()), static_cast<float>(fValue2.Get()));
    }

    Double pow(const Float& fValue, const Double& dValue)
    {
        return ::pow(static_cast<double>(fValue.Get()), static_cast<double>(dValue.Get()));
    }

    Float sqrt(const Float& fValue)
    {
        return ::sqrt(fValue.Get());
    }

    Float exp(const Float& fValue)
    {
        return ::exp(fValue.Get());
    }

// Double

    Double cos(const Double& dValue)
    {
        return ::cos((dValue*2.0*Double::PI).Get());
    }

    Double acos(const Double& dValue)
    {
        return Double(::acos(dValue.Get()))/(2.0*Double::PI);
    }

    Double sin(const Double& dValue)
    {
        return ::sin((dValue*2.0*Double::PI).Get());
    }

    Double asin(const Double& dValue)
    {
        return Double(::asin(dValue.Get()))/(2.0*Double::PI);
    }

    Double tan(const Double& dValue)
    {
        return ::tan((dValue*2.0*Double::PI).Get());
    }

    Double atan(const Double& dValue)
    {
        return Double(::atan(dValue.Get()))/(2.0*Double::PI);
    }

    Double atan2(const Double& dX, const Double& dY)
    {
        return Double(::atan2(dX.Get(), dY.Get()))/(2.0*Double::PI);
    }

    Double fabs(const Double& dValue)
    {
        return ::fabs(dValue.Get());
    }

    Double pow(const Double& dValue1, const Double& dValue2)
    {
        return ::pow(static_cast<double>(dValue1.Get()), static_cast<double>(dValue2.Get()));
    }

    Double pow(const Double& dValue, const Float& fValue)
    {
        return ::pow(static_cast<double>(dValue.Get()), static_cast<double>(fValue.Get()));
    }

    Double sqrt(const Double& dValue)
    {
        return ::sqrt(dValue.Get());
    }

    Double exp(const Double& dValue)
    {
        return ::exp(dValue.Get());
    }
}
